package base.reflecton;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;

import base.patterns.delegate.Delegate.NamedMethod;

public class ReflectionUtils {
	
	
	public static String getMethodDesription(Method delegateMethod) {
		StringBuilder sb = new StringBuilder();
		
		sb.append( String.format("%s", delegateMethod.toGenericString()) );

//		sb.append( String.format(" ReturnType %s", delegateMethod.getReturnType()) );
//		sb.append( String.format(" GenericReturnType %s", delegateMethod.getGenericReturnType()) );
//
//		Class<?>[] pType  = delegateMethod.getParameterTypes();
//		Type[] gpType = delegateMethod.getGenericParameterTypes();
//		for (int i = 0; i < pType.length; i++) {
//			sb.append( String.format(" ParameterType %s", pType[i]) );
//			sb.append( String.format(" GenericParameterType %s", gpType[i]) );
//		}
//
//		Class<?>[] xType  = delegateMethod.getExceptionTypes();
//		Type[] gxType = delegateMethod.getGenericExceptionTypes();
//		for (int i = 0; i < xType.length; i++) {
//			sb.append( String.format(" ExceptionType %s", xType[i]) );
//			sb.append( String.format(" GenericExceptionType %s", gxType[i]) );
//		}
		
		return sb.toString();
	}
	
	public static String reflectionLog(Object obj) {
		Class<?> currClass = obj.getClass();
		
		StringBuilder sb = new StringBuilder( String.format("%s {", currClass.getCanonicalName()) );
		
		while (null != currClass ){
			Field[] fields = currClass.getDeclaredFields();
			for (Field field : fields) {
				try {
					field.setAccessible(true);
					
					Object fieldValue = field.get(obj);
					String fieldName = field.getName();
					//String fieldType = null != fieldValue ? fieldValue.getClass().getCanonicalName() : field.getType().getCanonicalName();   
					sb.append( String.format("[%s = '%s']", fieldName, fieldValue) );
				} catch (Exception e) {
					sb.append( String.format("[%s = 'exception: %s']", field.getName(), e.getMessage()) );
				}
				
				if (null != currClass.getSuperclass()){
					sb.append(", ");
				}
			}
			currClass = currClass.getSuperclass();
			
		}
		sb.append("}");
		return sb.toString();
	}
	
	public static class MethodNameAnnotationPredicate implements Predicate{
		private String methodName;

		public MethodNameAnnotationPredicate(String methodName){
			this.methodName = methodName;
		}

		@Override
		public boolean evaluate(Object object) {
			Method m =(Method)object;
			NamedMethod annotation = m.getAnnotation(NamedMethod.class);
			return null != annotation && annotation.name().equalsIgnoreCase(methodName);
		}
		
		
	}
	
	public static Method findMethod(Object object, Predicate predicate){
		Method[] methods = object.getClass().getMethods();
		
		Method find =(Method) CollectionUtils.find(Arrays.asList(methods), predicate);
		return find;
	}
	
	public static Field findField(Object object, Predicate predicate){
		Field[] methods = object.getClass().getFields();
		
		Field find =(Field) CollectionUtils.find(Arrays.asList(methods), predicate);
		return find;
	}
}
